#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setFixedSize(this->width(), this->height());
    connect(ui->GenerateButton, &QPushButton::clicked, this, &Widget::GenerateButtonPressed);
    connect(ui->ExportButton, &QPushButton::clicked, this, &Widget::ExportButtonPressed);
    QPixmap pixmap = QPixmap("../images/peppa.jpeg").scaled(this->size());
    QPalette  palette (this->palette());
    palette .setBrush(QPalette::Background, QBrush(pixmap));
    this-> setPalette(palette);
    ui->ProList->setStyleSheet("background-color: rgb(255, 255, 255, 60);");
}

Widget::~Widget()
{
    delete ui;
}

std::mt19937 mt(time(0));

std::map<int, char> op;
std::map<int, int> pri;

struct node{
    int id, val;
    node(int id = -1, int val = -1):id(id), val(val){}
};

int tot, operatorNum, operandNum, bracketNum, ans;
int hasBracket[15], operators[15], operands[15];
int RPN[55], fac[105], numerators[15], denominators[15];
std::stack<int> opr;
std::stack<node> opd;

void init0(){
    op[10] = '+', op[11] = '-';
    op[12] = '*';
    op[14] = '(', op[15] = ')';
    pri[10] = 0, pri[11] = 0;
    pri[12] = 1, pri[13] = 1;
//    freopen("../result.txt", "w", stdout);
}

void init1(){
    tot = 0;
    for(int i = 0; i < 15; ++i){
        operators[i] = -1;
        operands[i] = -1;
        hasBracket[i] = -1;
    }
    while(!opr.empty()) opr.pop();
    while(!opd.empty()) opd.pop();
}

void init2(){
    tot = 0;
    while(!opr.empty()) opr.pop();
    while(!opd.empty()) opd.pop();
}

void init3(){
    tot = 0;
    for(int i = 0; i < 15; ++i){
        operators[i] = -1;
        numerators[i] = -1;
        denominators[i] = -1;
    }
}


int getNum(int l, int r){
    int ret = mt()%(r - l + 1) + l;
    return ret;
}

bool getOperands(){
    init2();
    if(hasBracket[0] != -1) opr.push(hasBracket[0]);
    RPN[tot++] = 0;
    for(int i = 1; i < operandNum; ++i){
        while(true){
            if(opr.empty() || opr.top() == 14 || pri[operators[i - 1]] > pri[opr.top()]){
                opr.push(operators[i - 1]);
                break;
            }
            RPN[tot++] = opr.top();
            opr.pop();
        }
        if(hasBracket[i] == 14){
            opr.push(hasBracket[i]);
        }
        RPN[tot++] = i;
        if(hasBracket[i] == 15){
            while(opr.top() != 14){
                RPN[tot++] = opr.top();
                opr.pop();
            }
            opr.pop();
        }
    }
    while(!opr.empty()){
        RPN[tot++] = opr.top();
        opr.pop();
    }
    for(int i = 0; i < tot; ++i){
        if(RPN[i] < 10){
            int x = getNum(1, 66);
            operands[RPN[i]] = x;
            opd.push(node(RPN[i], x));
            continue;
        }
        if(RPN[i] == 13){
            node b = opd.top(); opd.pop();
            node a = opd.top(); opd.pop();
            if(a.val%b.val == 0){
                opd.push(node(-1, a.val/b.val));
                continue;
            }
            if(b.id == -1) return false;
            int cnt = 0;
            for(int j = 1; j <= a.val; ++j){
                if(j >= 100) break;
                if(a.val%j) continue;
                fac[cnt++] = j;
            }
            int x =getNum(0, cnt - 1);
            operands[b.id] = fac[x];
            opd.push(node(-1, a.val/fac[x]));
        }else if(RPN[i] == 11){
            node b = opd.top(); opd.pop();
            node a = opd.top(); opd.pop();
            int dt = a.val - b.val;
            if(dt <= 0) return false;
            opd.push(node(-1, dt));
        }else{
            node b = opd.top(); opd.pop();
            node a = opd.top(); opd.pop();
            if(RPN[i] == 10) opd.push(node(-1, a.val + b.val));
            if(RPN[i] == 12) opd.push(node(-1, a.val*b.val));
        }
    }
    ans = opd.top().val; opd.pop();
    if(ans < 0 || ans > 100) return false;
    return true;
}


QString Widget::GenerateBracketsProblem(bool flag){
    init1();
    operatorNum = getNum(3, 5);
    operandNum = operatorNum + 1;

    bracketNum = std::min((int)(operandNum/2), getNum(2, 4));
    if(!flag) bracketNum = 0;

    for(int i = 0; i < operatorNum; ++i) operators[i] = getNum(10, 13);

    for(int i = 0; i < bracketNum*2; ++i){
        int x = getNum(0, operandNum - 1);
        while(hasBracket[x] != -1) x = getNum(0, operandNum - 1);
        hasBracket[x] = 0;
    }

    bool lf = true;
    for(int i = 0; i < operandNum; ++i){
        if(hasBracket[i] == -1) continue;
        if(lf) hasBracket[i] = 14;
        else hasBracket[i] = 15;
        lf = (!lf);
    }
    if(!getOperands()) return NULL;

    QString ret = "";
    if(hasBracket[0] != -1) ret += QString("(");
    ret += QString("%1").arg(operands[0]);
    for(int i = 1; i < operandNum; ++i){
        if(operators[i - 1] == 13) ret += QString("÷");
        else ret += QString("%1").arg(op[operators[i - 1]]);
        if(hasBracket[i] == 14) ret += QString("(");
        ret += QString("%1").arg(operands[i]);
        if(hasBracket[i] == 15) ret += QString(")");
    }
    ret += QString("=%1\n").arg(ans);
    return ret;
}

QString Widget::GenerateFractionProblem(){
    init3();
    operatorNum = mt()%3 + 3;
    operandNum = operatorNum + 1;
    for(int i = 0; i < operatorNum; ++i) operators[i] = mt()%2 + 10;
    denominators[0] = mt()%66 + 1;
    numerators[0] = mt()%(std::max(denominators[0] - 22, 1)) + 1;
    int g = std::__gcd(numerators[0], denominators[0]);
    numerators[0] /= g, denominators[0] /= g;
    int nowNume = numerators[0], nowDeno = denominators[0];
    for(int i = 1; i < operandNum; ++i){
        denominators[i] = mt()%66 + 1;
        numerators[i] = mt()%(std::max(denominators[i] - 22, 1)) + 1;
        g = std::__gcd(numerators[i], denominators[i]);
        numerators[i] /= g, denominators[i] /= g;
        g = std::__gcd(denominators[i], nowDeno);
        int lcm = nowDeno*denominators[i]/g;
        nowNume *= denominators[i]/g;
        if(operators[i - 1] == 10){
            nowNume += numerators[i]*nowDeno/g;
            if(nowNume >= nowDeno) return NULL;
        }else if(operators[i - 1] == 11){
            nowNume -= numerators[i]*nowDeno/g;
            if(nowNume <= 0) return NULL;
        }
        nowDeno = lcm;
        g = std::__gcd(nowNume, nowDeno);
        nowNume /= g, nowDeno /= g;
        if(nowNume > 100 || nowDeno > 100) return NULL;
    }
    QString ret = "";
    ret += QString("%1/%2").arg(numerators[0]).arg(denominators[0]);
    for(int i = 1; i < operandNum; ++i){
        ret += QString("%1").arg(op[operators[i - 1]]);
        ret += QString("%1/%2").arg(numerators[i]).arg(denominators[i]);
    }
    ret += QString("=%1/%2\n").arg(nowNume).arg(nowDeno);
    return ret;
}

void Widget::GenerateProblem(int num, bool hasBrac, bool hasFrac){
    init0();
//    qDebug("GenerateProblem");
    ui->ProList->setPlainText("");
    while(num--){
        int x = getNum(0, 8);
        QString prob = NULL;
        if(x <= 2){
            prob = GenerateBracketsProblem(false);
            while(prob == NULL) prob = GenerateBracketsProblem(false);
        }
        else if(x <= 5){
            if(!hasBrac){
                ++num;
                continue;
            }
            prob = GenerateBracketsProblem(true);
            while(prob == NULL) prob = GenerateBracketsProblem(true);
        }
        else{
            if(!hasFrac){
                ++num;
                continue;
            }
            prob = GenerateFractionProblem();
            while(prob == NULL) prob = GenerateFractionProblem();
        }
        QString lst = ui->ProList->toPlainText();
        ui->ProList->setPlainText(lst + "\n" + prob);
    }
}

void Widget::GenerateButtonPressed(){
    int num = ui->ProNumSpinBox->value();
    bool hasBrac = ui->HasBracket->checkState();
    bool hasFrac = ui->HasFraction->checkState();
//    qDebug("GenerateButtonPressed");
//    qDebug("%d %d %d", num, hasBrac, hasFrac);
    GenerateProblem(num, hasBrac, hasFrac);
}

void Widget::ExportButtonPressed(){
    QString txt = ui->ProList->toPlainText();
    QFile file("../result.txt");
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    file.write(txt.toUtf8());
    file.close();
    QMessageBox *msgBox;
    msgBox = new QMessageBox("导出成功",
        "您好，题目已经导出成功",
        QMessageBox::NoIcon,
        0,
        QMessageBox::Ok | QMessageBox::Default,
        0);
   msgBox->show();
}
